import com.bulenkov.darcula.DarculaLaf;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.util.ArrayList;

/**
 * Created by ospip on 2017/11/29.
 * Copyright (c) 2017 LLAP. All rights reserved.
 */
public class Client extends JFrame {
    private int workerID = 0;
    private ArrayList<JButton> buttonList;
    private String multiCastIP = "224.116.8.1";
    private int port = 817;
    private int requestPort = 1926;
    private InetAddress group;
    private MulticastSocket msocket;
    private DatagramPacket pack;
    byte[] buf;
    private String targetIP = "192.168.43.209";
    private ArrayList<QueuePanel> panelList;
    private Logger logger;


    public Client() {
        super("Client");
        try {
            UIManager.setLookAndFeel(new DarculaLaf());
        } catch (Exception e) {
            try {
                UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
            }
            catch (Exception ex) {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                }
                catch (Exception exc) {
                    System.out.println("Substance Raven Graphite failed to initialize");
                }
            }
        }
        this.setSize(600, 600);
        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        this.setLocationRelativeTo(getOwner());
        this.setLayout(new BorderLayout());
        logger = new Logger("Client");
        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(30, 30, 30, 30));
        this.add("Center", panel);

        try {
            workerID = Integer.parseInt(InetAddress.getLocalHost().getHostAddress().split("\\.")[3]) & 0x3ff;
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
            workerID = 0;
        }

        buttonList = new ArrayList<>();
        panelList = new ArrayList<>();
        connect();
        new Thread(() -> {
//            System.out.println("Getting queue information from server...");
            while(true) {
                try {
                    msocket.receive(pack);
                    String message = new String(pack.getData(), 0, pack.getLength());
//                    System.out.println("Received: " + message);
                    String[] list = message.split("\\|");
                    targetIP = list[list.length - 1];
                    this.setTitle(targetIP);

//                    System.out.println("Get Request");
                    for (QueuePanel q : panelList) {
                        panel.remove(q);
                    }
                    this.panelList.clear();
                    panel.setLayout(null);
                    panel.setLayout(new GridLayout(list.length - 1, 1, 0, 15));
                    for (int i = 0; i < list.length - 1; i++) {
//                        System.out.println("Adding " + i);
                        String[] args = list[i].split(",");
                        int waitCount = Integer.parseInt(args[1]);
                        panelList.add(new QueuePanel(targetIP, workerID, requestPort, panelList.size(), args[0], waitCount, logger));
                        panel.add(panelList.get(panelList.size() - 1));
                    }
//                    System.out.println("Redraw");
                    panel.updateUI();
                }
                catch (Exception e) {}
            }
        }).start();

    }

    public void connect() {
        try {
            msocket = new MulticastSocket(port);
            group = InetAddress.getByName(multiCastIP);
            msocket.joinGroup(group);
            buf = new byte[512];
            pack = new DatagramPacket(buf, buf.length, group, port);
        }
        catch (Exception e) {}
    }

    public static void main(String[] args) {
        BroadcastThread.main(new String[0]);
        new Client().setVisible(true);
    }
}
class QueuePanel extends JPanel {
    private JButton request;
    private JButton requestVIP;
    private JLabel waiting;
    private JPanel bag;
    private int queueNo;
    private Logger logger;
    private String targetIP;
    private int workerID;
    private int requestPort = 1926;

    public QueuePanel(String targetIP, int workerID, int requestPort, int n, String comment, int w, Logger logger) {
        super();
        this.targetIP = targetIP;
        this.workerID = workerID;
        this.queueNo = n;
        this.requestPort = requestPort;
        this.logger = logger;
        this.setSize(500, 100);
        this.setLayout(new GridLayout(1, 2));
        request = new JButton(comment);
        requestVIP = new JButton("VIP");
        waiting = new JLabel("排队人数：" + w);
        bag = new JPanel(new GridLayout(1, 2, 15, 0));
        bag.add(requestVIP);
        bag.add(waiting);
        this.add(request);
        this.add(bag);
        request.addActionListener(e -> {
            this.sendRequest();
        });
        requestVIP.addActionListener(e -> {
            this.sendRequest(1);
        });
    }

    private void sendRequest(int p) {
        /* Args: %worker%/%act%/%queueNo%[/%workerName% | /%priority%]
         *  Example: 42/poll/一号窗口/1
         *  Example: 51/add/2
         *  Example: 51/add/2/1
         *
         */
        if (targetIP == "") return;
        String request = String.format("%d/add/%d/%d", workerID, queueNo, p);
        try {
            Socket socket = new Socket(targetIP, requestPort);
            PrintWriter sout = new PrintWriter(socket.getOutputStream(), false);
            sout.println(request);
            sout.flush();
            BufferedReader callback = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String response = callback.readLine();
            JOptionPane.showMessageDialog(null, "取到号码" + response);
            logger.log("取到号码" + response);
            callback.close();
            sout.close();
            socket.close();
        }
        catch (Exception ex) {
            System.out.println("Request Error: " + ex.getMessage());
        }
    }
    private void sendRequest() {this.sendRequest(0);}
}